package com.geek.water.controller;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.geek.water.constant.CodeConstant;
import com.geek.water.constant.MessageConstant;
import com.geek.water.dto.DeviceCreateDTO;
import com.geek.water.dto.DeviceUpdateDTO;
import com.geek.water.entity.Area;
import com.geek.water.entity.Device;
import com.geek.water.entity.DeviceData;
import com.geek.water.result.Result;
import com.geek.water.service.DeviceService;
import com.geek.water.vo.DevicePageQueryVO;
import com.geek.water.entity.Site;
import com.geek.water.entity.Customer;
import com.geek.water.service.AreaService;
import com.geek.water.service.SiteService;
import com.geek.water.service.CustomerService;
import com.geek.water.service.GlobalWaterPriceTierService;
import com.geek.water.mapper.DeviceDataMapper;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;

/**
 * @author yangwenqi
 * @decs TODO
 * @date 2025/7/25
 */

/**
 * 设备管理接口
 */
@RestController
@RequestMapping("/admin/device")
@RequiredArgsConstructor
@Slf4j
@Api(tags = "后台系统 - 设备档案管理")
public class DeviceController {
    private final DeviceService deviceService;
    private final AreaService areaService;
    private final SiteService siteService;
    private final CustomerService customerService;
    private final GlobalWaterPriceTierService globalWaterPriceTierService;
    private final DeviceDataMapper deviceDataMapper;

    @ApiOperation("条件分页查询设备列表")
    @PreAuthorize("hasAuthority('device:view')")
    @GetMapping("page")
    public Result page(DevicePageQueryVO devicePageQueryVO) {
        Page<Device> page = deviceService.findPage(devicePageQueryVO);
        if (page != null && !CollectionUtils.isEmpty(page.getRecords())) {
            return new Result(CodeConstant.SUCCESS, MessageConstant.QUERY_DEVICE_SUCCESS, page);
        }
        return new Result(CodeConstant.FAIL, MessageConstant.QUERY_DEVICE_FAIL);
    }

    @ApiOperation("新增设备")
    @PreAuthorize("hasAuthority('device:operate')")
    @PostMapping
    public Result save(@RequestBody DeviceCreateDTO dto) {
        // 检查序列号唯一性
        if (!deviceService.isSerialNoUnique(dto.getSerialNo(), null)) {
            return new Result(CodeConstant.FAIL, MessageConstant.DEVICE_SERIAL_EXIST);
        }

        Device device = new Device();
        BeanUtils.copyProperties(dto, device);

        // 给 status 设置默认值
        if (device.getStatus() == null || device.getStatus().isEmpty()) {
            device.setStatus("online");
        }

        boolean flag = deviceService.save(device);
        if (flag) {
            return new Result(CodeConstant.SUCCESS, MessageConstant.ADD_DEVICE_SUCCESS);
        }
        return new Result(CodeConstant.FAIL, MessageConstant.ADD_DEVICE_FAIL);
    }

    @ApiOperation("通过ID查询设备")
    @PreAuthorize("hasAuthority('device:view')")
    @GetMapping("{id}")
    public Result findById(@PathVariable Long id) {
        try {
            Device device = deviceService.getById(id);
            if (device == null) {
                return new Result(CodeConstant.FAIL, MessageConstant.QUERY_DEVICE_FAIL);
            }

            // 构建设备详情，包含抄表数据
            Map<String, Object> deviceDetail = new HashMap<>();
            deviceDetail.put("id", device.getId());
            deviceDetail.put("areaId", device.getAreaId());
            deviceDetail.put("model", device.getModel());
            deviceDetail.put("serialNo", device.getSerialNo());
            deviceDetail.put("status", device.getStatus());
            deviceDetail.put("lastHeartbeat", device.getLastHeartbeat());
            deviceDetail.put("createdAt", device.getCreatedAt());

            // 获取当前抄表读数（来自device表）
            BigDecimal currentMeterReading = device.getCurrentReading();
            deviceDetail.put("currentMeterReading", currentMeterReading);

            // 获取上月抄表读数（从device_data表获取7月末数据）
            BigDecimal lastMeterReading = getLastReadingFromDeviceData(id, "2025-07");
            deviceDetail.put("lastMeterReading", lastMeterReading);

            // 计算本月用水量
            BigDecimal monthlyUsage = BigDecimal.ZERO;
            if (currentMeterReading != null && lastMeterReading != null) {
                monthlyUsage = currentMeterReading.subtract(lastMeterReading);
                if (monthlyUsage.compareTo(BigDecimal.ZERO) < 0) {
                    monthlyUsage = BigDecimal.ZERO;
                }
            }
            deviceDetail.put("monthlyUsage", monthlyUsage);

            log.info("设备 {} 详情查询成功: 当前读数={}, 上月读数={}, 本月用水量={}",
                    id, currentMeterReading, lastMeterReading, monthlyUsage);

            return new Result(CodeConstant.SUCCESS, MessageConstant.QUERY_DEVICE_SUCCESS, deviceDetail);
        } catch (Exception e) {
            log.error("查询设备详情失败 - 设备ID: {}, 错误: {}", id, e.getMessage(), e);
            return new Result(CodeConstant.FAIL, "查询设备详情失败: " + e.getMessage());
        }
    }

    @ApiOperation("更新设备信息")
    @PreAuthorize("hasAuthority('device:operate')")
    @PutMapping
    public Result update(@RequestBody DeviceUpdateDTO deviceDTO) {
        // 将DTO转换为实体对象，避免暴露不必要字段
        Device device = new Device();
        device.setId(deviceDTO.getId());

        // 只更新允许修改的字段
        if (deviceDTO.getAreaId() != null) {
            device.setAreaId(deviceDTO.getAreaId());
        }
        if (deviceDTO.getStatus() != null) {
            device.setStatus(deviceDTO.getStatus());
        }

        boolean flag = deviceService.updateById(device);
        return flag ?
                new Result(CodeConstant.SUCCESS, MessageConstant.UPDATE_DEVICE_SUCCESS) :
                new Result(CodeConstant.FAIL, MessageConstant.UPDATE_DEVICE_FAIL);
    }

    @ApiOperation("删除设备")
    @PreAuthorize("hasAuthority('device:operate')")
    @DeleteMapping("{id}")
    public Result deleteById(@PathVariable Long id) {
        boolean flag = deviceService.deleteById(id);
        if (flag) {
            return new Result(CodeConstant.SUCCESS, MessageConstant.DELETE_DEVICE_SUCCESS);
        }
        return new Result(CodeConstant.FAIL, MessageConstant.DELETE_DEVICE_FAIL);
    }

    @ApiOperation("更新设备抄表读数")
    @PreAuthorize("hasAuthority('device:operate')")
    @PutMapping("/{id}/meterReading")
    public Result updateMeterReading(
            @PathVariable Long id,
            @RequestParam BigDecimal currentReading,
            @RequestParam(required = false) String billingPeriod) {
        try {
            log.info("开始更新设备抄表读数 - 设备ID: {}, 当前读数: {}, 计费周期: {}", id, currentReading, billingPeriod);

            Device device = deviceService.getById(id);
            if (device == null) {
                log.warn("设备不存在 - 设备ID: {}", id);
                return new Result(CodeConstant.FAIL, "设备不存在");
            }

            if (currentReading.compareTo(BigDecimal.ZERO) < 0) {
                log.warn("抄表读数不能为负数 - 设备ID: {}, 读数: {}", id, currentReading);
                return new Result(CodeConstant.FAIL, "抄表读数不能为负数");
            }

            // 更新设备当前读数，历史读数保存在device_data表中
            device.setCurrentReading(currentReading);

            // 计费周期由业务逻辑处理，这里不再设置

            boolean updated = deviceService.updateById(device);
            if (updated) {
                log.info("设备抄表读数更新成功 - 设备ID: {}", id);
                return new Result(CodeConstant.SUCCESS, "抄表读数更新成功");
            }
            log.error("设备抄表读数更新失败 - 设备ID: {}", id);
            return new Result(CodeConstant.FAIL, "抄表读数更新失败");
        } catch (Exception e) {
            log.error("更新设备抄表读数失败 - 设备ID: {}, 错误: {}", id, e.getMessage(), e);
            return new Result(CodeConstant.FAIL, "更新失败: " + e.getMessage());
        }
    }

    @ApiOperation("获取设备监控数据")
    @PreAuthorize("hasAuthority('device:data')")
    @GetMapping("{id}/data")
    public Result getDeviceData(
            @PathVariable Long id,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") String startTime,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") String endTime) {
        // 将前端传入的字符串解析为 LocalDateTime
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime start = LocalDateTime.parse(startTime, fmt);
        LocalDateTime end   = LocalDateTime.parse(endTime,   fmt);

        List<DeviceData> data = deviceService.getDeviceData(id, start, end);
        return new Result(
                CodeConstant.SUCCESS,
                MessageConstant.QUERY_DEVICE_SUCCESS,
                data
        );
    }

    @ApiOperation("获取设备历史读数")
    @PreAuthorize("hasAuthority('device:view')")
    @GetMapping("{id}/history")
    public Result getDeviceHistory(
            @PathVariable Long id,
            @RequestParam(required = false) String billingPeriod) {
        try {
            // 如果没有指定计费周期，默认获取当前月份
            if (billingPeriod == null || billingPeriod.isEmpty()) {
                LocalDate now = LocalDate.now();
                billingPeriod = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            }

            // 获取上个月末的抄表读数
            BigDecimal lastReading = getLastReadingFromDeviceData(id, billingPeriod);

            Map<String, Object> result = new HashMap<>();
            result.put("deviceId", id);
            result.put("billingPeriod", billingPeriod);
            result.put("lastReading", lastReading);

            return new Result(CodeConstant.SUCCESS, "获取历史读数成功", result);
        } catch (Exception e) {
            log.error("获取设备 {} 历史读数失败: {}", id, e.getMessage());
            return new Result(CodeConstant.FAIL, "获取历史读数失败: " + e.getMessage());
        }
    }

    @ApiOperation("上传设备数据")
    @PreAuthorize("hasAuthority('device:operate')")
    @PostMapping("data")
    public Result uploadDeviceData(@RequestBody DeviceData deviceData) {
        boolean success = deviceService.uploadDeviceData(deviceData);
        return success ?
                new Result(CodeConstant.SUCCESS, MessageConstant.UPLOAD_DEVICE_DATA_SUCCESS) :
                new Result(CodeConstant.FAIL, MessageConstant.UPLOAD_DEVICE_DATA_FAIL);
    }

    @ApiOperation("获取设备计费汇总信息")
    @PreAuthorize("hasAuthority('device:view')")
    @GetMapping("billing/summary")
    public Result getDeviceBillingSummary(
            @RequestParam(value = "currentPage", defaultValue = "1") Integer currentPage,
            @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
            @RequestParam(value = "customerId", required = false) Long customerId,
            @RequestParam(value = "billingPeriod", required = false) String billingPeriod) {
        try {
            DevicePageQueryVO deviceQuery = new DevicePageQueryVO();
            deviceQuery.setCurrentPage(currentPage);
            deviceQuery.setPageSize(pageSize);
            deviceQuery.setBillingPeriod(billingPeriod);

            Page<Device> page = deviceService.findPage(deviceQuery);

            // 如果指定了客户ID，需要过滤设备
            if (customerId != null) {
                List<Device> filteredDevices = page.getRecords().stream()
                        .filter(device -> {
                            try {
                                if (device.getAreaId() != null) {
                                    Area area = areaService.getById(device.getAreaId());
                                    if (area != null && area.getSiteId() != null) {
                                        Site site = siteService.getById(area.getSiteId());
                                        return site != null && customerId.equals(site.getCustomerId());
                                    }
                                }
                                return false;
                            } catch (Exception e) {
                                log.warn("过滤设备时出错: {}", e.getMessage());
                                return false;
                            }
                        })
                        .collect(Collectors.toList());

                // 重新创建分页结果
                page.setRecords(filteredDevices);
                page.setTotal(filteredDevices.size());
            }

            // 转换为计费汇总数据
            List<Map<String, Object>> billingSummary = page.getRecords().stream().map(device -> {
                Map<String, Object> summary = new HashMap<>();
                summary.put("deviceId", device.getId());
                summary.put("serialNo", device.getSerialNo());
                summary.put("model", device.getModel());

                // 获取计费周期末的读数（当前读数）
                BigDecimal currentReading = getCurrentReadingFromDeviceData(device.getId(), billingPeriod);

                // 获取上个月末的读数（上次读数）
                BigDecimal lastReading = getLastReadingFromDeviceData(device.getId(), billingPeriod);

                // 计费周期由业务逻辑处理
                summary.put("billingPeriod", billingPeriod != null ? billingPeriod : "2025-08");
                summary.put("status", device.getStatus());

                // 计算用水量逻辑
                BigDecimal usageAmount = BigDecimal.ZERO;

                if (currentReading != null && lastReading != null) {
                    // 判断是否为当前月份（8月）
                    LocalDate now = LocalDate.now();
                    String currentMonth = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));

                    if (billingPeriod.equals(currentMonth)) {
                        // 当前月份：使用device表的currentReading作为当前读数
                        BigDecimal deviceCurrentReading = device.getCurrentReading();
                        if (deviceCurrentReading != null) {
                            currentReading = deviceCurrentReading;
                            usageAmount = deviceCurrentReading.subtract(lastReading);
                            log.info("设备 {} 当前月份 {} 用水量计算: 当前读数={}, 上次读数={}, 用水量={}",
                                    device.getId(), billingPeriod, deviceCurrentReading, lastReading, usageAmount);
                        }
                    } else {
                        // 历史月份：使用该月末读数 - 上个月末读数
                        usageAmount = currentReading.subtract(lastReading);
                        log.info("设备 {} 历史月份 {} 用水量计算: 当前读数={}, 上次读数={}, 用水量={}",
                                device.getId(), billingPeriod, currentReading, lastReading, usageAmount);
                    }

                    // 确保用水量不为负数
                    if (usageAmount.compareTo(BigDecimal.ZERO) < 0) {
                        usageAmount = BigDecimal.ZERO;
                        log.warn("设备 {} 计费周期 {} 用水量计算为负数，设置为0", device.getId(), billingPeriod);
                    }
                }

                summary.put("currentReading", currentReading);
                summary.put("lastReading", lastReading);
                summary.put("usageAmount", usageAmount);

                // 计算预估费用（使用阶梯水费）
                BigDecimal estimatedCost = BigDecimal.ZERO;
                if (usageAmount.compareTo(BigDecimal.ZERO) > 0) {
                    try {
                        estimatedCost = globalWaterPriceTierService.calculateGlobalTieredPrice(usageAmount);
                        log.info("设备 {} 预估费用计算: 用水量={}, 预估费用={}", device.getId(), usageAmount, estimatedCost);
                    } catch (Exception e) {
                        log.error("设备 {} 预估费用计算失败: {}", device.getId(), e.getMessage());
                        // 如果阶梯水费计算失败，使用默认计算方式
                        estimatedCost = usageAmount.multiply(new BigDecimal("3.50")); // 默认单价3.50元/吨
                    }
                }
                summary.put("estimatedCost", estimatedCost);

                // 获取关联的区域和站点信息
                if (device.getAreaId() != null) {
                    try {
                        Area area = areaService.getById(device.getAreaId());
                        if (area != null) {
                            summary.put("areaName", area.getName());
                            summary.put("areaId", area.getId());



                            // 获取站点信息
                            if (area.getSiteId() != null) {
                                Site site = siteService.getById(area.getSiteId());
                                if (site != null) {
                                    summary.put("siteName", site.getName());
                                    summary.put("siteId", site.getId());

                                    // 获取客户信息
                                    if (site.getCustomerId() != null) {
                                        Customer customer = customerService.getById(site.getCustomerId());
                                        if (customer != null) {
                                            summary.put("customerName", customer.getName());
                                            summary.put("customerId", customer.getId());
                                        }
                                    }
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.error("获取设备{}关联信息失败: {}", device.getId(), e.getMessage());
                        // 设置默认值，确保前端能正常显示
                        summary.put("areaName", "未知区域");
                        summary.put("siteName", "未知站点");
                        summary.put("customerName", "未知客户");
                    }
                } else {
                    // 设备没有关联区域，设置默认值
                    summary.put("areaName", "未分配区域");
                    summary.put("siteName", "未分配站点");
                    summary.put("customerName", "未分配客户");
                }

                return summary;
            }).collect(Collectors.toList());

            Map<String, Object> result = new HashMap<>();
            result.put("records", billingSummary);
            result.put("total", page.getTotal());
            result.put("current", page.getCurrent());
            result.put("size", page.getSize());

            return new Result(CodeConstant.SUCCESS, "获取设备计费汇总成功", result);
        } catch (Exception e) {
            log.error("获取设备计费汇总失败", e);
            return new Result(CodeConstant.FAIL, "获取设备计费汇总失败: " + e.getMessage());
        }
    }

    @ApiOperation("测试接口：获取所有设备数量")
    @PreAuthorize("hasAuthority('device:view')")
    @GetMapping("test/count")
    public Result getDeviceCount() {
        try {
            long count = deviceService.count();
            List<Device> allDevices = deviceService.list();

            Map<String, Object> result = new HashMap<>();
            result.put("totalCount", count);
            result.put("devices", allDevices.stream().map(device -> {
                Map<String, Object> deviceInfo = new HashMap<>();
                deviceInfo.put("id", device.getId());
                deviceInfo.put("serialNo", device.getSerialNo());
                deviceInfo.put("model", device.getModel());
                deviceInfo.put("areaId", device.getAreaId());
                // billingPeriod 是查询参数，不是设备属性，设置为默认值或从其他地方获取
                deviceInfo.put("billingPeriod", "2025-08"); // 计费周期由业务逻辑处理
                return deviceInfo;
            }).collect(Collectors.toList()));

            return new Result(CodeConstant.SUCCESS, "获取设备数量成功", result);
        } catch (Exception e) {
            log.error("获取设备数量失败", e);
            return new Result(CodeConstant.FAIL, "获取设备数量失败: " + e.getMessage());
        }
    }

    /**
     * 从设备数据表获取当前计费周期末的抄表读数
     * 业务逻辑：获取指定计费周期末的抄表读数
     * 例如：计费周期是2025-01，获取2025-01-31的抄表读数
     */
    private BigDecimal getCurrentReadingFromDeviceData(Long deviceId, String billingPeriod) {
        try {
            // 如果没有指定计费周期，默认获取当前月份
            if (billingPeriod == null || billingPeriod.isEmpty()) {
                LocalDate now = LocalDate.now();
                billingPeriod = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            }

            // 解析计费周期
            String[] parts = billingPeriod.split("-");
            if (parts.length != 2) {
                return BigDecimal.ZERO;
            }

            int year = Integer.parseInt(parts[0]);
            int month = Integer.parseInt(parts[1]);

            // 构建计费周期末的日期（月末）
            String currentMonthEnd = String.format("%04d-%02d", year, month);

            log.info("设备 {} 查询计费周期 {} 末的抄表读数", deviceId, currentMonthEnd);

            // 查询当前计费周期末的数据
            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DeviceData> wrapper =
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
            wrapper.eq(DeviceData::getDeviceId, deviceId)
                    .likeRight(DeviceData::getReadingDate, currentMonthEnd)
                    .orderByDesc(DeviceData::getReadingDate); // 按日期倒序，确保获取最新的记录

            DeviceData currentData = deviceDataMapper.selectOne(wrapper);

            if (currentData != null) {
                log.info("设备 {} 计费周期 {} 末抄表读数: {}", deviceId, currentMonthEnd, currentData.getValue());
                return currentData.getValue();
            }

            log.warn("设备 {} 没有找到计费周期 {} 末的抄表数据", deviceId, currentMonthEnd);
            return BigDecimal.ZERO;
        } catch (Exception e) {
            log.error("获取设备 {} 的当前读数失败: {}", deviceId, e.getMessage());
            return BigDecimal.ZERO;
        }
    }

    /**
     * 从设备数据表获取上个月末的抄表读数
     * 业务逻辑：每月末统计一次，获取上个月末的抄表读数
     * 例如：当前是8月，获取7月末的抄表读数
     */
    private BigDecimal getLastReadingFromDeviceData(Long deviceId, String billingPeriod) {
        try {
            // 如果没有指定计费周期，默认获取当前月份
            if (billingPeriod == null || billingPeriod.isEmpty()) {
                LocalDate now = LocalDate.now();
                billingPeriod = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            }

            // 解析计费周期
            String[] parts = billingPeriod.split("-");
            if (parts.length != 2) {
                return BigDecimal.ZERO;
            }

            int year = Integer.parseInt(parts[0]);
            int month = Integer.parseInt(parts[1]);

            // 获取上个月末的抄表读数
            // 如果当前是8月，就获取7月末的数据
            String lastMonth;
            if (month == 1) {
                lastMonth = String.format("%04d-%02d", year - 1, 12);
            } else {
                lastMonth = String.format("%04d-%02d", year, month - 1);
            }

            log.info("设备 {} 查询上个月 {} 的抄表读数", deviceId, lastMonth);

            // 查询上个月的数据，获取月末的抄表记录
            // 由于device_data表存储的是每月末的抄表数据，直接查询上个月即可
            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<DeviceData> wrapper =
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
            wrapper.eq(DeviceData::getDeviceId, deviceId)
                    .likeRight(DeviceData::getReadingDate, lastMonth)
                    .orderByDesc(DeviceData::getReadingDate); // 按日期倒序，确保获取最新的记录

            DeviceData lastData = deviceDataMapper.selectOne(wrapper);

            if (lastData != null) {
                log.info("设备 {} 上个月 {} 抄表读数: {}", deviceId, lastMonth, lastData.getValue());
                return lastData.getValue();
            }

            log.warn("设备 {} 没有找到上个月 {} 的抄表数据", deviceId, lastMonth);
            return BigDecimal.ZERO;
        } catch (Exception e) {
            log.error("获取设备 {} 的上次读数失败: {}", deviceId, e.getMessage());
            return BigDecimal.ZERO;
        }
    }
}